前言:
findViewById 是每一个 Android 开发者的必经之路,同样也是噩梦。为了提高开发效率,准备在项目中使用 ButterKnife(PS:感谢JakeWharton大神),本文基于8.5.1 版本官方文档翻译,不同的版本在用法上可能会差异,实际使用时,请参考官网文档。
Github 地址
官方文档
ButterKnife 介绍
- Android 开发者的福音,专为 Android View 设计的绑定注解,专治 findViewById。
- 配合 AndroidStudio 插件使用,一键生成 view field。。。爽歪歪
- 还有其他很多有用的注解。。。
ButterKnife引入
Download
1 | dependencies { |
Library Module中使用
###在 Module 的 build.gradle 添加如下配置:
1 | buildscript { |
1 | apply plugin: 'com.android.library' |
使用
使用 R2 代替 R1
2
3
4class ExampleActivity extends Activity{
(R2.id.user) EditText username;
(R2.id.pwd) EditText pwd;
}
控件绑定
用 @BindView 注解,并注明view id,ButterKnife 会自动查找控件,并转换成layout文件中指定的类型。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class ExampleActivity extends Activity{
(R.id.title)
TextView title;
(R.id.subtitle)
TextView subtitle;
(R.id.footer)
TextView footer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
资源绑定
@BindArray, @BindBitmap, @BindBool, @BindColor, @BindDimen, @BindDrawable, @BindFloat, @BindInt, @BindString1
2
3
4
5
6
7class ExampleActivity extends Activity {
(R.string.title) String title;
(R.drawable.graphic) Drawable graphic;
int red; // int or ColorStateList field (R.color.red)
// int (for pixel size) or float (for exact value) field (R.dimen.spacer) Float spacer;
// ...
}
非Activity绑定
ButterKnife 提供了 bind 的几个重载,只要传入根布局,便可以在任何对象中使用注解绑定。
例如在 Fragment 中:1
2
3
4
5
6
7
8
9
10
11
12public class FancyFragment extends Fragment {
(R.id.button1) Button button1;
(R.id.button2) Button button2;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}
还有一种比较常见的场景,是 adapter 中的 ViewHolder1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class MyAdapter extends BaseAdapter{
public View getView(int position, View view, ViewGroup parent){
ViewHolder holder;
if(view != null){
holder = (ViewHolder) view.getTag();
}else{
view = inflater.inflate(R.layout.whatever,parent,false);
holder = new ViewHolder(view);
view.setTag(holder);
}
holder.name.setText("John Doe");
// etc...
}
return view;
}
1 | static class ViewHolder{ |
ButterKnife 可以在任何调用 fingViewById 的地方使用。
提供的其他绑定 API :
使用Activity作为跟布局在任意对象中进行绑定。如果你使用了类似MVC的编程模式,你可以对controller使用它的Activity用ButterKnife.bind(this, activity)进行绑定。
使用ButterKnife.bind(this)绑定一个布局的子布局。如果你在布局中使用了
标签并且在自定义的控件构造时inflate这个布局,你可以在inflate之后立即调用它。或者,你可以在onFinishInflate()回调中使用它。
View Lists
一次性将多个 Views 绑定到一个 List 或数组中1
2 ({R.id.first_name,R.id.middle_name,R.id.last_name})
List<EditText> nameViews;
我们可以通过 apply
函数在列表中的所有view上执行一个动作。1
2ButterKnife.apply(nameViews,DISABLE);
ButterKnife.apply(nameViews,ENABLED,false);
Action
和 Setter
接口指定一些动作1
2
3
4
5
6
7
8
9
10
11
12static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>(){
@Override
public void apply(View view, int index){
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View,Boolean> ENABLED = new ButterKnife.Setter<View,Boolean>(){
@Override
public void set(View view,Boolean value,int index){
view.setEnabled(value);
}
};
Android 中的 Property
属性也可以使用 apply
方法进行设置:1
ButterKnife.apply(nameViews,View.ALPHA,0.0f);
监听器绑定
事件绑定示例
监听器可以自动绑定到指定的方法上1
2
3
4 (R.id.submit)
public void submit(View view){
// TODO something
}
监听器方法的参数是可选的1
2
3
4 (R.id.submit)
public void submit(){
// TODO something
}
指定一个特定的类型,ButterKnife 会将它自动转换1
2
3
4 (R.id.submit)
public void sayHi(Button button){
button.setText("Hello!");
}
在一个方法上指定多个 view id ,多个 view 共用一个处理方法。1
2
3
4
5
6
7
8@OnClick({R.id.door1,R.id.door2,R.id.door3})
public void pickDoor(DoorView door){
if(door.hasPrizeBehind()){
Toast.makeText(this,"You win!",LENGTH_SHORT).show();
}else{
Toast.makeText(this,"Try again",LENGTH_SHORT).show();
}
}
自定义 view 绑定事件监听不需要指定ID1
2
3
4
5
6public class FancyButton extends Button{
public void onClick(){
// todo something!
}
}
ButterKnife 事件监听注解
可以看到,我们常用的事件,ButterKniffe 都提供了注解。
多个方法的监听绑定
当一个监听器包含多个回调函数时,使用函数的注解能够对其中任何一个函数进行绑定。每一个注解都会绑定到一个默认的回调。你也可以使用callback参数来指定一个其他函数作为回调。
1 | (R.id.list_view) |
解除绑定
Fragment 的生命周期和Activity是不同的。如果在 onCreateView
中绑定了 Fragment,我们应该在 onDestoryView
方法中解除绑定。ButterKnife 返回了 Unbinder 实例来完成这个操作。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class FancyFragment extends Fragment{
(R.id.button1) Button button1;
(R.id.button2) Button button2;
private Unbinder unbinder;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
可选绑定
默认情况下, @Bind 和 监听绑定是必须得,如果目标view没有找到的话,ButterKnife会抛出异常。
我们可以通过 @Nullable 标注字段或者 @Optional 标注方法,防止异常的抛出,创建可选的绑定。1
2
3
4
5 (R.id.might_not_be_there) TextView mightNotBeThere;
void onMaybeMissingClicked() { (R.id.maybe_missing)
// TODO ...
}
彩蛋
ButterKnife 提供了 findViewById 方法的简化版: findById,可以在Activity,View 和 Dialog 中查找view。 它使用泛型对返回值类型进行自动转换,不需要我们进行强转。1
2
3
4View view = LayoutInflater.from(context).inflate(R.layout.thing, null);
TextView firstName = ButterKnife.findById(view, R.id.first_name);
TextView lastName = ButterKnife.findById(view, R.id.last_name);
ImageView photo = ButterKnife.findById(view, R.id.photo);
author: @ygwang